﻿///
///  This source code is freeware and is provided on an "as is" basis without warranties of any kind, 
///  whether express or implied, including without limitation warranties that the code is free of defect, 
///  fit for a particular purpose or non-infringing.  The entire risk as to the quality and performance of 
///  the code is with the end user.
///
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;
using System.IO;
using System.Web;
using Microsoft.SharePoint.Administration;

namespace Banshee
{
    class Program
    {
        static StreamWriter log = null;
        static StreamWriter errorlog = null;
        static int counter = 0;
        static Guid publishingSiteFeatureGuid = new Guid("f6924d36-2fa8-4f0b-b16d-06b7250180fa");
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("Usage: banshee.exe http://sitecollectionurl");
                Console.WriteLine("OR     banshee.exe -farm");
                return;
            }
            try
            {
                string datestr = DateTime.Now.ToString("yyyyMMdd_HHmmss");
                log = File.CreateText("navnodelog_" + datestr + ".txt");
                errorlog = File.CreateText("errorlog_" + datestr + ".txt");
                if (args[0].ToLowerInvariant().Equals("-farm"))
                {
                    ProcessFarm();
                }
                else
                {
                    using (SPSite site = new SPSite(args[0]))
                    {
                        ProcessSite(site);
                    }
                }
            }
            catch (Exception ex2)
            {
                Console.WriteLine(ex2);
                errorlog.WriteLine("Error in Main.  " + ex2.Message);
                errorlog.Flush();
            }
            log.Close();
            errorlog.Close();
            Console.WriteLine("Processing completed. {0} navigation nodes found.\nPlease press <enter> to close this window", counter.ToString());
            Console.ReadLine();
        }

        private static void ProcessFarm()
        {
            SPFarm farm = SPFarm.Local;
            SPWebServiceCollection wsvc = new SPWebServiceCollection(farm);
            foreach (SPWebService currentwsvc in wsvc) {
                foreach (SPWebApplication webapp in currentwsvc.WebApplications)
                {
                    try
                    {
                        foreach (SPSite currentsite in webapp.Sites)
                        {
                            try
                            {
                                Console.WriteLine("Processing site collection: {0}", currentsite.Url);
                                ProcessSite(currentsite);
                            }
                            catch (Exception ex3)
                            {
                                Console.WriteLine(ex3);
                                errorlog.WriteLine("Error in ProcessFarm.  " + ex3.Message);
                                errorlog.Flush();

                            }
                            finally
                            {
                                if (currentsite != null)
                                {
                                    currentsite.Dispose();
                                }
                            }
                        }
                    }
                    catch (Exception ex4)
                    {
                        Console.WriteLine(ex4);
                        errorlog.WriteLine("Error in ProcessFarm.  " + ex4.Message);
                        errorlog.Flush();

                    }
                }
            }

        }

        private static void ProcessSite(SPSite site)
        {
            try
            {
                if (!isPublishingFeatureEnabled(site))
                {
                    Console.WriteLine("  Publishing feature is not enabled, cannot be affected. Skipping...");
                    return;
                }

                foreach (SPWeb currentweb in site.AllWebs)
                {
                    try
                    {
                        Console.WriteLine("  Processing web {0}", currentweb.Url);
                        if (currentweb.Navigation != null)
                        {
                            if (currentweb.Navigation.TopNavigationBar != null)
                            {
                                foreach (SPNavigationNode currentnode in currentweb.Navigation.TopNavigationBar)
                                {
                                    ProcessNode(currentnode, currentweb, "GlobalNavigation");
                                }
                            }
                            if (currentweb.Navigation.QuickLaunch != null)
                            {
                                foreach (SPNavigationNode currentnode in currentweb.Navigation.QuickLaunch)
                                {

                                    ProcessNode(currentnode, currentweb, "CurrentNavigation");
                                }
                            }
                        }


                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                        errorlog.WriteLine("Error in ProcessSite.  " + ex.Message);
                        errorlog.Flush();

                    }
                    finally
                    {
                        if (currentweb != null)
                        {
                            currentweb.Dispose();
                        }
                    }
                }
            }
            catch (Exception ex5)
            {
                Console.WriteLine(ex5);
                Console.WriteLine("An error occurred with site collection {0}", site.Url);
                errorlog.WriteLine("Error in ProcessSite with site collection {0}: {1} ", site.Url, ex5.Message);
                errorlog.Flush();
            }
        }

        private static bool isPublishingFeatureEnabled(SPSite site)
        {
            bool result=true; // we need to check it in case of error            
            try{
                foreach (SPFeature f in site.Features)
                {
                    if (f.DefinitionId.Equals(publishingSiteFeatureGuid))
                    {                        
                        return true;
                    }
                }
                result = false; // if we did not return previously, publishing is not enabled, we can skip it.
            }
            catch  (Exception ex)
            {
                Console.WriteLine(ex);
            }
            return result;
        }

        private static void ProcessNode(SPNavigationNode currentnode, SPWeb currentweb, string type)
        {
            //Console.WriteLine("{0} {1} {2}", currentnode.Title, currentnode.Url, currentnode.Properties["NodeType"] != null ? currentnode.Properties["NodeType"].ToString() : "[null]");

            if (!currentnode.Url.Contains(".") && !currentnode.IsExternal && currentnode.Properties["NodeType"] != null && !currentnode.Properties["NodeType"].ToString().Equals("Area"))
            {
                log.WriteLine("web name:{0}; web url:{1};location: {5}; navnode title:{2}; navnode url:{3}, navnode type:{4}", currentweb.Title, currentweb.Url, currentnode.Title, currentnode.Url, currentnode.Properties["NodeType"].ToString(), type);
                log.Flush();
                counter++;
            }
            if (!currentnode.IsExternal && currentnode.Properties["NodeType"] != null && currentnode.Properties["NodeType"].ToString().Equals("Heading"))
            {
                foreach (SPNavigationNode currentCnode in currentnode.Children)
                {
                    ProcessNode(currentCnode, currentweb, type);
                }
            }

        }
    }
}
